{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7HEiR6F5NE3V"
      },
      "source": [
        "# About face detect demo\n",
        "This demo will show you: how to build the face detection processing pipeline accelerated by TensorRT through the BMF framework. After encapsulating the face detection processing workflow into a BMF module, you can use a small amount of code to build a face detection processing pipeline BMF Graph, which reflects the good compatibility of the BMF framework with AI deep learning frameworks such as Torch and TensorRT."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "adEpMANmKFZM"
      },
      "source": [
        "# Install\n",
        "\n",
        "## 1. Install TensorRT\n",
        "First, we need to install TensorRT's binary and python API"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "RzjYTHQricAs"
      },
      "outputs": [],
      "source": [
        "!mkdir -p trt\n",
        "%cd trt\n",
        "!wget https://developer.nvidia.com/downloads/compute/machine-learning/tensorrt/secure/8.6.1/tars/TensorRT-8.6.1.6.Linux.x86_64-gnu.cuda-12.0.tar.gz\n",
        "%env version=8.6.1.6\n",
        "%env arch=x86_64\n",
        "%env cuda=cuda-12.0\n",
        "!tar -xzvf TensorRT-${version}.Linux.${arch}-gnu.${cuda}.tar.gz\n",
        "!python3 -m pip install --upgrade pip\n",
        "%cd TensorRT-8.6.1.6/python\n",
        "!python3 -m pip install tensorrt-8.6.1-cp310-none-linux_x86_64.whl\n",
        "!python3 -m pip install tensorrt_lean-8.6.1-cp310-none-linux_x86_64.whl\n",
        "!python3 -m pip install tensorrt_dispatch-8.6.1-cp310-none-linux_x86_64.whl\n",
        "%cd -\n",
        "%cd TensorRT-8.6.1.6/uff\n",
        "!python3 -m pip install uff-0.6.9-py2.py3-none-any.whl\n",
        "%cd -\n",
        "%cd TensorRT-8.6.1.6/graphsurgeon\n",
        "!python3 -m pip install graphsurgeon-0.4.6-py2.py3-none-any.whl\n",
        "%cd -\n",
        "%cd TensorRT-8.6.1.6/onnx_graphsurgeon\n",
        "!python3 -m pip install onnx_graphsurgeon-0.3.12-py2.py3-none-any.whl\n",
        "%cd ..\n",
        "!rm -rf python uff graphsurgeon onnx_graphsurgeon\n",
        "%cd /content\n",
        "%env LIBRARY_PATH=/usr/local/cuda/lib64/stubs:/content/trt/TensorRT-8.6.1.6/lib\n",
        "%env LD_LIBRARY_PATH=/content/trt/TensorRT-8.6.1.6/lib:/usr/lib64-nvidia:/content/trt/TensorRT-8.6.1.6/lib\n",
        "%env PATH=/opt/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/tools/node/bin:/tools/google-cloud-sdk/bin:/content/trt/TensorRT-8.6.1.6/bin"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "o1dXoeOmKyAk"
      },
      "source": [
        "## Configure environment variables for TRT"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "6MJp08yQHE2f"
      },
      "outputs": [],
      "source": [
        "%env LIBRARY_PATH=/usr/local/cuda/lib64/stubs:/content/trt/TensorRT-8.6.1.6/lib\n",
        "%env LD_LIBRARY_PATH=/content/trt/TensorRT-8.6.1.6/lib:/usr/lib64-nvidia:/content/trt/TensorRT-8.6.1.6/lib\n",
        "%env PATH=/opt/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/tools/node/bin:/tools/google-cloud-sdk/bin:/content/trt/TensorRT-8.6.1.6/bin"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-IVElGWJWbqD"
      },
      "source": [
        "## pip install BMF packages"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "IjiiVnD9Aua-"
      },
      "outputs": [],
      "source": [
        "!pip install BabitMF-GPU"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "AuU2xFfsb3VV"
      },
      "source": [
        "## install wurlitzer\n",
        "\n",
        "This package is installed to show the BMF C++ logs in the colab console, otherwise only python logs are printed. This step is not necessary if you're not in a Colab or iPython notebook environment."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "VoXqpHLh5aBM"
      },
      "outputs": [],
      "source": [
        "!pip install wurlitzer\n",
        "%load_ext wurlitzer"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hC4ZKWhOd7g6"
      },
      "source": [
        "# 2. BMF processing pipeline programming\n",
        "*   Download the Face detect model and use TRT to convert it to .engine\n",
        "*   Implement BMF Module of face detection.\n",
        "*  Display the results."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4Q-x00orgL-S"
      },
      "source": [
        "## Download the Face detect model and use TRT to convert it to .engine"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "FQ-Y4B78u7V_"
      },
      "outputs": [],
      "source": [
        "!wget https://github.com/BabitMF/bmf/releases/download/files/models.tar.gz\n",
        "!tar -zvxf models.tar.gz\n",
        "!cp models/version-RFB-640.onnx .\n",
        "!trtexec --onnx=version-RFB-640.onnx --buildOnly --saveEngine=version-RFB-640.engine"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "E3mvqVqAgViw"
      },
      "source": [
        "## Implement BMF Module of face detection.\n",
        "\n",
        "Implement the face detection Module, which obtains the decoded frame output by the Decoder, converts pix_fmt to RGB format and sends it to the detection model, then filters the results and draws a bounding box in each of the output frame."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "kYmNwD6X-zSU"
      },
      "outputs": [],
      "source": [
        "%%writefile /content/trt_face_detect.py\n",
        "\n",
        "import tensorrt as trt\n",
        "import torch\n",
        "import torch.nn.functional as F\n",
        "import numpy as np\n",
        "import sys\n",
        "import time\n",
        "\n",
        "if sys.version_info.major == 2:\n",
        "    from Queue import Queue\n",
        "else:\n",
        "    from queue import Queue\n",
        "\n",
        "import PIL\n",
        "from PIL import Image\n",
        "\n",
        "sys.path.append(\"../../\")\n",
        "\n",
        "from bmf import *\n",
        "import bmf.hmp as mp\n",
        "\n",
        "def NMS(bounding_boxes, confidence_score, threshold = 0.5):\n",
        "    if len(bounding_boxes) == 0:\n",
        "        return [], []\n",
        "\n",
        "    boxes = np.array(bounding_boxes)\n",
        "\n",
        "    start_x = boxes[:, 0]\n",
        "    start_y = boxes[:, 1]\n",
        "    end_x = boxes[:, 2]\n",
        "    end_y = boxes[:, 3]\n",
        "\n",
        "    score = np.array(confidence_score)\n",
        "\n",
        "    picked_boxes = []\n",
        "    picked_score = []\n",
        "\n",
        "    areas = (end_x - start_x + 1) * (end_y - start_y + 1)\n",
        "\n",
        "    order = np.argsort(score)\n",
        "\n",
        "    while order.size > 0:\n",
        "        index = order[-1]\n",
        "\n",
        "        picked_boxes.append(bounding_boxes[index])\n",
        "        picked_score.append(confidence_score[index])\n",
        "\n",
        "        x1 = np.maximum(start_x[index], start_x[order[:-1]])\n",
        "        x2 = np.minimum(end_x[index], end_x[order[:-1]])\n",
        "        y1 = np.maximum(start_y[index], start_y[order[:-1]])\n",
        "        y2 = np.minimum(end_y[index], end_y[order[:-1]])\n",
        "\n",
        "        w = np.maximum(0.0, x2 - x1 + 1)\n",
        "        h = np.maximum(0.0, y2 - y1 + 1)\n",
        "        intersection = w * h\n",
        "\n",
        "        ratio = intersection / (areas[index] + areas[order[:-1]] - intersection)\n",
        "\n",
        "        left = np.where(ratio < threshold)\n",
        "        order = order[left]\n",
        "\n",
        "    return picked_boxes, picked_score\n",
        "\n",
        "class trt_face_detect(Module):\n",
        "\n",
        "    def __init__(self, node=None, option=None):\n",
        "        self.node_ = node\n",
        "        self.option_ = option\n",
        "\n",
        "        if option is None:\n",
        "            Log.log(LogLevel.ERROR, \"Option is none\")\n",
        "            return\n",
        "\n",
        "        if \"model_path\" in option.keys():\n",
        "            self.model_path_ = option[\"model_path\"]\n",
        "\n",
        "        if \"label_to_frame\" in option.keys():\n",
        "            self.label_frame_flag_ = option[\"label_to_frame\"]\n",
        "\n",
        "        if \"input_shapes\" in option.keys():\n",
        "            self.input_shapes_ = option[\"input_shapes\"]\n",
        "\n",
        "        start_time = time.time()\n",
        "\n",
        "        logger = trt.Logger(trt.Logger.ERROR)\n",
        "        with open(self.model_path_, 'rb') as f:\n",
        "            engine_buffer = f.read()\n",
        "        self.engine_ = trt.Runtime(logger).deserialize_cuda_engine(\n",
        "            engine_buffer)\n",
        "\n",
        "        if self.engine_ is None:\n",
        "            Log.log(LogLevel.ERROR, \"Failed building engine!\")\n",
        "            return\n",
        "        Log.log(LogLevel.INFO, \"Succeeded building engine!\")\n",
        "\n",
        "        self.num_io_tensors_ = self.engine_.num_io_tensors\n",
        "        self.tensor_names_ = [\n",
        "            self.engine_.get_tensor_name(i)\n",
        "            for i in range(self.num_io_tensors_)\n",
        "        ]\n",
        "        self.num_inputs_ = [self.engine_.get_tensor_mode(self.tensor_names_[i]) for i in range(self.num_io_tensors_)] \\\n",
        "                           .count(trt.TensorIOMode.INPUT)\n",
        "        assert self.num_inputs_ == len(\n",
        "            self.input_shapes_.keys()\n",
        "        ), \"The number of input_shapes doesn't match the number of model's inputs.\"\n",
        "        self.num_outputs_ = [self.engine_.get_tensor_mode(self.tensor_names_[i]) for i in range(self.num_io_tensors_)] \\\n",
        "                           .count(trt.TensorIOMode.OUTPUT)\n",
        "\n",
        "        self.context_ = self.engine_.create_execution_context()\n",
        "        self.stream_ = mp.current_stream(mp.kCUDA)\n",
        "\n",
        "        for i in range(self.num_inputs_):\n",
        "            self.context_.set_input_shape(\n",
        "                self.tensor_names_[0],\n",
        "                self.input_shapes_[self.tensor_names_[0]])\n",
        "\n",
        "        self.output_dict_ = dict()\n",
        "        for i in range(self.num_inputs_, self.num_io_tensors_):\n",
        "            self.output_dict_[self.tensor_names_[i]] = mp.empty(\n",
        "                self.context_.get_tensor_shape(self.tensor_names_[i]),\n",
        "                device=mp.kCUDA,\n",
        "                dtype=self.to_scalar_types(\n",
        "                    self.engine_.get_tensor_dtype(self.tensor_names_[i])))\n",
        "\n",
        "        self.frame_cache_ = Queue()\n",
        "        self.in_frame_num_ = 1\n",
        "        self.out_frame_num_ = 1\n",
        "\n",
        "        self.eof_received_ = False\n",
        "\n",
        "        Log.log(LogLevel.ERROR, \"Load model takes\", (time.time() - start_time))\n",
        "\n",
        "    def reset(self):\n",
        "        self.eof_received_ = False\n",
        "        while not self.frame_cache_.empty():\n",
        "            self.frame_cache_.get()\n",
        "\n",
        "    def to_scalar_types(self, trt_dtype):\n",
        "        dtype_map = {\n",
        "            trt.float32: mp.kFloat32,\n",
        "            trt.float16: mp.kHalf,\n",
        "            trt.int32: mp.kInt32,\n",
        "            trt.int8: mp.kInt8,\n",
        "            trt.uint8: mp.kUInt8,\n",
        "        }\n",
        "        return dtype_map[trt_dtype]\n",
        "\n",
        "    def pre_process(self, torch_image_array):\n",
        "        input_shape = list(self.input_shapes_.values())[0]\n",
        "        # input shape is the shape of trt engine\n",
        "        batch = input_shape[0]\n",
        "        channel = input_shape[1]\n",
        "        width = input_shape[3]\n",
        "        height = input_shape[2]\n",
        "\n",
        "        input_tensor = torch.stack(torch_image_array).float()\n",
        "        input_tensor = torch.permute(input_tensor, [0, 3, 1, 2])\n",
        "        input_tensor = F.interpolate(input_tensor,\n",
        "                                     size=(height, width),\n",
        "                                     mode='bilinear')\n",
        "\n",
        "        torch_mean = torch.empty((1, 3, 1, 1), device=\"cuda\").fill_(0.5)\n",
        "        torch_std = torch.empty((1, 3, 1, 1), device=\"cuda\").fill_(0.5)\n",
        "\n",
        "        input_tensor = (input_tensor / 255 - torch_mean) / torch_std\n",
        "\n",
        "        return input_tensor\n",
        "\n",
        "    def post_process(self, input_pil_arrays, boxes, scores):\n",
        "        output_list = []\n",
        "        boxes_data = []\n",
        "        scores_data = []\n",
        "        for image_id in range(len(input_pil_arrays)):\n",
        "\n",
        "            image = input_pil_arrays[image_id]\n",
        "            output_data = []\n",
        "            for index in range(len(boxes[image_id])):\n",
        "                if (scores[image_id][index][1]) > 0.8:\n",
        "                    box = (boxes[image_id][index])\n",
        "                    x1 = int(box[0] * image.size[0])\n",
        "                    y1 = int(box[1] * image.size[1])\n",
        "                    x2 = int(box[2] * image.size[0])\n",
        "                    y2 = int(box[3] * image.size[1])\n",
        "                    boxes_data.append([x1, y1, x2, y2])\n",
        "                    scores_data.append(scores[image_id][index][1])\n",
        "\n",
        "            nms_boxes, nms_scores = NMS(boxes_data, scores_data)\n",
        "            output_list.append(nms_boxes)\n",
        "        return output_list\n",
        "\n",
        "    def label_frame(self, input_frames, pil_image_array, detect_result_list):\n",
        "        from PIL import ImageDraw\n",
        "        output_frame_list = []\n",
        "        for index_frame in range(len(pil_image_array)):\n",
        "            image = pil_image_array[index_frame]\n",
        "            draw = ImageDraw.Draw(image)\n",
        "            for index_box in range(len(detect_result_list[index_frame])):\n",
        "                detect_result = detect_result_list[index_frame][index_box]\n",
        "                draw.rectangle([\n",
        "                    detect_result[0], detect_result[1], detect_result[2],\n",
        "                    detect_result[3]\n",
        "                ])\n",
        "            del draw\n",
        "            numpy_image = np.asarray(image)\n",
        "            H420 = mp.PixelInfo(mp.kPF_YUV420P)\n",
        "            rgb = mp.PixelInfo(mp.kPF_RGB24)\n",
        "\n",
        "            frame = mp.Frame(mp.from_numpy(np.ascontiguousarray(numpy_image)),\n",
        "                             rgb)\n",
        "            out_frame = VideoFrame(frame).reformat(H420)\n",
        "\n",
        "            out_frame.pts = input_frames[index_frame].pts\n",
        "            out_frame.time_base = input_frames[index_frame].time_base\n",
        "            output_frame_list.append(out_frame)\n",
        "        return output_frame_list\n",
        "\n",
        "    def inference(self):\n",
        "        frame_num = min(self.frame_cache_.qsize(), self.in_frame_num_)\n",
        "        input_frames = []\n",
        "\n",
        "        if frame_num == 0:\n",
        "            return [], []\n",
        "        torch_image_array = []\n",
        "        pil_image_array = []\n",
        "        for i in range(frame_num):\n",
        "            vf = self.frame_cache_.get()\n",
        "            if (vf.frame().device() == mp.Device('cpu')):\n",
        "                vf = vf.cuda()\n",
        "            input_frames.append(vf)\n",
        "\n",
        "            rgb = mp.PixelInfo(mp.kPF_RGB24)\n",
        "            torch_vf = torch.from_dlpack(vf.reformat(rgb).frame().plane(0))\n",
        "            numpy_vf = torch_vf.cpu().numpy()\n",
        "            torch_image_array.append(torch_vf)\n",
        "            pil_image_array.append(PIL.Image.fromarray(numpy_vf))\n",
        "\n",
        "        input_tensor = self.pre_process(torch_image_array)\n",
        "\n",
        "        for i in range(self.num_inputs_):\n",
        "            self.context_.set_tensor_address(\n",
        "                self.tensor_names_[i],\n",
        "                int(input_tensor.contiguous().data_ptr()))\n",
        "\n",
        "        for i in range(self.num_inputs_, self.num_io_tensors_):\n",
        "            self.context_.set_tensor_address(\n",
        "                self.tensor_names_[i],\n",
        "                int(self.output_dict_[self.tensor_names_[i]].data_ptr()))\n",
        "\n",
        "        self.context_.execute_async_v3(self.stream_.handle())\n",
        "\n",
        "        scores = self.output_dict_[\"scores\"].cpu().numpy()\n",
        "        boxes = self.output_dict_[\"boxes\"].cpu().numpy()\n",
        "\n",
        "        detect_result_list = self.post_process(pil_image_array, boxes, scores)\n",
        "        if self.label_frame_flag_ == 1:\n",
        "            result_frames = self.label_frame(input_frames, pil_image_array,\n",
        "                                             detect_result_list)\n",
        "            return result_frames, detect_result_list\n",
        "\n",
        "        return input_frames, detect_result_list\n",
        "\n",
        "    def process(self, task):\n",
        "        input_queue = task.get_inputs()[0]\n",
        "        output_queue_0 = task.get_outputs()[0]\n",
        "        output_queue_size = len(task.get_outputs())\n",
        "        if output_queue_size >= 2:\n",
        "            output_queue_1 = task.get_outputs()[1]\n",
        "\n",
        "        while not input_queue.empty():\n",
        "            pkt = input_queue.get()\n",
        "            if pkt.timestamp == Timestamp.EOF:\n",
        "                self.eof_received_ = True\n",
        "            if pkt.is_(VideoFrame):\n",
        "                self.frame_cache_.put(pkt.get(VideoFrame))\n",
        "\n",
        "        while self.frame_cache_.qsize(\n",
        "        ) >= self.in_frame_num_ or self.eof_received_:\n",
        "            out_frames, detect_result_list = self.inference()\n",
        "            for idx, frame in enumerate(out_frames):\n",
        "                pkt = Packet(frame)\n",
        "                pkt.timestamp = frame.pts\n",
        "                output_queue_0.put(pkt)\n",
        "\n",
        "                if (output_queue_size >= 2):\n",
        "                    pkt = Packet(detect_result_list[idx])\n",
        "                    pkt.timestamp = frame.pts\n",
        "                    output_queue_1.put(pkt)\n",
        "\n",
        "            if self.frame_cache_.empty():\n",
        "                break\n",
        "\n",
        "        if self.eof_received_:\n",
        "            for key in task.get_outputs():\n",
        "                task.get_outputs()[key].put(Packet.generate_eof_packet())\n",
        "                Log.log_node(LogLevel.DEBUG, self.node_, \"output stream\",\n",
        "                             \"done\")\n",
        "            task.timestamp = Timestamp.DONE\n",
        "\n",
        "        return ProcessResult.OK\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FvItCS_eM-ux"
      },
      "source": [
        "## Download a face video (made from Youtube Faces Database)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "O7kH9pQaKmol"
      },
      "outputs": [],
      "source": [
        "!wget https://github.com/BabitMF/bmf/releases/download/files/files.tar.gz\n",
        "!tar -zvxf files.tar.gz\n",
        "!cp files/face.mp4 ."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "TluhhW6TNBeB"
      },
      "outputs": [],
      "source": [
        "%env BMF_LOG_LEVEL=INFO"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "UmkF2cplgmDO"
      },
      "source": [
        "## Build BMF Graph pipeline"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "wti6gSKDA3yL"
      },
      "outputs": [],
      "source": [
        "%%writefile /content/trt.py\n",
        "\n",
        "import sys\n",
        "import torch\n",
        "import numpy as np\n",
        "\n",
        "import bmf\n",
        "from bmf import Log, LogLevel\n",
        "\n",
        "\n",
        "def main():\n",
        "\n",
        "    # v1.engine can be built by the command: trtexec --onnx=version-RFB-640.onnx --buildOnly --saveEngine=version-RFB-640.engine\n",
        "\n",
        "    (bmf.graph().decode({\n",
        "        \"input_path\": \"./face.mp4\",\n",
        "        \"video_params\": {\n",
        "            \"hwaccel\": \"cuda\",\n",
        "        }\n",
        "    })[\"video\"].module(\"trt_face_detect\", option = {\n",
        "            \"model_path\": \"version-RFB-640.engine\",\n",
        "            \"label_to_frame\": 1,\n",
        "            \"input_shapes\": {\n",
        "                \"input\": [1, 3, 480, 640]\n",
        "            }\n",
        "        }).encode(\n",
        "        None, {\n",
        "            \"output_path\": \"./trt_out.mp4\",\n",
        "            \"video_params\": {\n",
        "                \"codec\": \"h264_nvenc\",\n",
        "                \"bit_rate\": 5000000,\n",
        "            }\n",
        "        }).run())\n",
        "\n",
        "\n",
        "if __name__ == \"__main__\":\n",
        "    main()\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "PkEp8bKrAXQX"
      },
      "outputs": [],
      "source": [
        "!python3 trt.py"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jW8qsu-Og68d"
      },
      "source": [
        "## Display the processed video"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "sQuyM8EQ_3wa"
      },
      "outputs": [],
      "source": [
        "from IPython.display import HTML\n",
        "from base64 import b64encode\n",
        "\n",
        "def show_video(video_path, video_width = 800):\n",
        "\n",
        "  video_file = open(video_path, \"r+b\").read()\n",
        "\n",
        "  video_url = f\"data:video/mp4;base64,{b64encode(video_file).decode()}\"\n",
        "\n",
        "  return HTML(f\"\"\"<video width={video_width} controls><source src=\"{video_url}\"></video>\"\"\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "g09dbMaLdSF8"
      },
      "outputs": [],
      "source": [
        "# show output video\n",
        "show_video(\"./face.mp4\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "EPVVdQKRdSF8"
      },
      "outputs": [],
      "source": [
        "# show input video\n",
        "show_video(\"./trt_out.mp4\")"
      ]
    }
  ],
  "metadata": {
    "accelerator": "GPU",
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
